﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace WWWSiteHelper
{
    public class AttributesProvider
    {
        public class Factory
        {
            public static AttributesProvider GetInstance()
            {
                return new AttributesProvider(
                    GetKnowledge(new String[] { Properties.Resources.Maths }.ToList()),
                    GetList(new String[] { Properties.Resources.Empty }.ToList()),
                    GetList(new String[] { Properties.Resources.Empty }.ToList()));
            }

            private static TagAttributeCountingKnowledge GetKnowledge(ICollection<string> sitesContents)
            {
                List<TagAttributeCountingKnowledge> knowledges = sitesContents
                    .Select(content => TagAttributeCountingKnowledge.parse(content))
                    .ToList();
                return new TagAttributeCountingKnowledge(knowledges);
            }

            private static TagAttributeKnowledge GetList(ICollection<string> sitesContents)
            {
                List<TagAttributeCountingKnowledge> knowledges = sitesContents
                    .Select(content => TagAttributeCountingKnowledge.parse(content))
                    .ToList();
                return new TagAttributeKnowledge(new TagAttributeCountingKnowledge(knowledges));
            }
        }

        private AttributesProvider(TagAttributeCountingKnowledge knowledge, TagAttributeKnowledge whitelist, TagAttributeKnowledge blacklist)
        {
            this.Knowledge = knowledge;
            this.Whitelist = whitelist;
            this.Blacklist = blacklist;
        }

        public List<string> GetAttributes(String tagName)
        {
            SortedSet<string> blackAttributes = Blacklist.getAttributes(tagName);
            SortedSet<string> knowledgeAttrs = new SortedSet<string>(Knowledge.getAttributes(tagName).Keys);
            List<string> result = Knowledge.getAttributes(tagName)
                .Where(attr => !blackAttributes.Contains(attr.Key))
                .OrderBy(attr => attr.Value)
                .Select(attr => attr.Key)
                .ToList();
            result.AddRange(Whitelist.getAttributes(tagName)
                .Where(attr => !blackAttributes.Contains(attr) && !knowledgeAttrs.Contains(attr)));
            return result;
        }

        public TagAttributeKnowledge.BasicTag GetHint(string tagPrefix)
        {
            SortedSet<string> blackTags = new SortedSet<string>(Blacklist.getTags().Select(basicTag => basicTag.Name));
            try
            {
                KeyValuePair<string, TagAttributeCountingKnowledge.TagTraitCount> element = Knowledge.getTags()
                    .Where(tag => tag.Key.StartsWith(tagPrefix) && !blackTags.Contains(tag.Key))
                    .OrderBy(tag => tag.Value.Opened)
                    .Last();
                bool isSelfClosing = (element.Value.Closed==0);
                return new TagAttributeKnowledge.BasicTag(element.Key, isSelfClosing);
            }
            catch (InvalidOperationException)
            {
                try
                {
                    return Whitelist.getTags()
                        .Where(tag => tag.Name.StartsWith(tagPrefix) && !blackTags.Contains(tag.Name))
                        .First();
                }
                catch (InvalidOperationException)
                {
                    return null;
                }
            }
        }

        public string GetHint(String tagName, String attrPrefix)
        {
            SortedSet<string> blackAttributes = Blacklist.getAttributes(tagName);
            try
            {
                return Knowledge.getAttributes(tagName)
                    .Where(attribute => attribute.Key.StartsWith(attrPrefix) && !blackAttributes.Contains(attribute.Key))
                    .OrderBy(attribute => attribute.Value)
                    .Last()
                    .Key;
            }
            catch (InvalidOperationException)
            {
                try
                {
                    return Whitelist.getAttributes(tagName)
                        .Where(attr => attr.StartsWith(attrPrefix) && !blackAttributes.Contains(attr))
                        .First();
                }
                catch (InvalidOperationException)
                {
                    return null;
                }
            }
        }

        public TagAttributeCountingKnowledge Knowledge { get; private set; }

        public TagAttributeKnowledge Whitelist { get; private set; }

        public TagAttributeKnowledge Blacklist { get; private set; }
    }
}
